home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 3: CDPD 3 / Almathera Ten on Ten - Disc 3: CDPD3.iso / ab20 / ab20_archive / datacomm / xpr / xprzmodem-2.51.lzh / xprzmodem2.5 / Zm.c < prev    next >
C/C++ Source or Header  |  1991-11-17  |  19KB  |  796 lines

  1. /**********************************************************************
  2.  *   Z M . C
  3.  *    ZMODEM protocol primitives
  4.  *    01-19-87  Chuck Forsberg Omen Technology Inc
  5.  *
  6.  * 29 July 89:
  7.  * Major overhaul by Rick Huebner for adaptation to Amiga XPR protocol spec
  8.  *
  9.  * 28 October 89:
  10.  * Converted to Lattice C 5.04
  11.  *
  12.  * 15 November 1991
  13.  * Code added to support CRC-32 by William M. Perkins.
  14.  **********************************************************************/
  15.  
  16. #include <proto/all.h>
  17. #include <exec/types.h>
  18. #include <ctype.h>
  19. #include <stdio.h>
  20. #include <string.h>
  21. #include "xproto.h"
  22. #include "zmodem.h"
  23. #include "xprzmodem.h"
  24. #include "zcrc.h"
  25.  
  26. static char *frametypes[] =
  27. {
  28.    "Carrier Lost",         /* -3 */
  29.    "TIMEOUT",              /* -2 */
  30.    "ERROR",                /* -1 */
  31. #define FTOFFSET 3
  32.    "ZRQINIT",
  33.    "ZRINIT",
  34.    "ZSINIT",
  35.    "ZACK",
  36.    "ZFILE",
  37.    "ZSKIP",
  38.    "ZNAK",
  39.    "ZABORT",
  40.    "ZFIN",
  41.    "ZRPOS",
  42.    "ZDATA",
  43.    "ZEOF",
  44.    "ZFERR",
  45.    "ZCRC",
  46.    "ZCHALLENGE",
  47.    "ZCOMPL",
  48.    "ZCAN",
  49.    "ZFREECNT",
  50.    "ZCOMMAND",
  51.    "ZSTDERR",
  52.    "xxxxx"
  53. #define FRTYPES 22      /* Total number of frame types in this array */
  54.                         /*  not including psuedo negative entries */
  55.    };
  56.  
  57. static UBYTE DLE_actions[] =
  58. {
  59.    0,0,0,0,0,0,0,0, 0,0,0,0,0,2,0,0, 1,1,0,1,0,0,0,0, 1,0,0,0,0,0,0,0,
  60.    0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
  61.    0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
  62.    0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
  63.  
  64.    0,0,0,0,0,0,0,0, 0,0,0,0,0,2,0,0, 1,1,0,1,0,0,0,0, 0,0,0,0,0,0,0,0,
  65.    0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
  66.    0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
  67.    0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0
  68.    };
  69.  
  70. /**********************************************************
  71.  *    void zsbhdr(struct Vars *v, USHORT type)
  72.  *
  73.  * Send ZMODEM binary header hdr of type type
  74.  **********************************************************/
  75. void zsbhdr(struct Vars *v, USHORT type)
  76. {
  77.    UBYTE  *hdr = v->Txhdr;
  78.    short  n;
  79.    USHORT crc;
  80.    ULONG  crc32;
  81.  
  82.    xsendline(v, ZPAD);
  83.    xsendline(v, ZDLE);
  84.  
  85.    if (v->Crc32t = v->Txfcs32)    /* zsbh32() */
  86.    {
  87.       xsendline(v, ZBIN32);
  88.       zsendline(v, (UBYTE) type);
  89.  
  90. #ifdef DEBUGLOG
  91.       mysprintf(v->Msgbuf, "zsbh32: %s %lx\n", frametypes[type + FTOFFSET],
  92.          v->Txpos);
  93.       dlog(v, v->Msgbuf);
  94. #endif
  95.       crc32 = 0xFFFFFFFFL;
  96.       crc32 = UPDC32(type, crc32);
  97.  
  98.       for (n = 4; --n >= 0; ++hdr)
  99.       {
  100.      crc32 = UPDC32((0377 & *hdr), crc32);
  101.      zsendline(v, *hdr);
  102.      }
  103.       crc32 = ~crc32;
  104.       for (n = 4; --n >= 0;)
  105.       {
  106.      zsendline(v, (int) crc32);
  107.      crc32 >>= 8;
  108.      }
  109.       }
  110.    else
  111.    {
  112.       xsendline(v, ZBIN);
  113.       zsendline(v, (UBYTE) type);
  114.  
  115. #ifdef DEBUGLOG
  116.       mysprintf(v->Msgbuf, "zsbhdr: %s %lx\n", frametypes[type + FTOFFSET],
  117.          v->Txpos);
  118.       dlog(v, v->Msgbuf);
  119. #endif
  120.       crc = updcrc(type, 0);
  121.       for (n = 4; --n >= 0; )
  122.       {
  123.      zsendline(v, *hdr);
  124.      crc = updcrc(((USHORT) (*hdr++)), crc);
  125.      }
  126.  
  127.       crc = updcrc(((USHORT) 0), crc);
  128.       crc = updcrc(((USHORT) 0), crc);
  129.       zsendline(v, (UBYTE) (crc >> 8));
  130.       zsendline(v, (UBYTE) crc);
  131.       }
  132.    }    /* End of void zsbhdr() */
  133.  
  134. /**********************************************************
  135.  *    void zshhdr(struct Vars *v, USHORT type)
  136.  *
  137.  * Send ZMODEM HEX header hdr of type type
  138.  **********************************************************/
  139. void zshhdr(struct Vars *v, USHORT type)
  140. {
  141.    UBYTE *hdr = v->Txhdr;
  142.    short n;
  143.    USHORT crc;
  144.  
  145. #ifdef DEBUGLOG
  146.    mysprintf(v->Msgbuf, "zshhdr: %s %lx\n", frametypes[type + FTOFFSET],
  147.       v->Rxbytes);
  148.    dlog(v, v->Msgbuf);
  149. #endif
  150.    sendline(v, ZPAD);
  151.    sendline(v, ZPAD);
  152.    sendline(v, ZDLE);
  153.    sendline(v, ZHEX);
  154.    zputhex(v, (UBYTE) type);
  155.    v->Crc32t = 0;
  156.  
  157.    crc = updcrc(type, 0);
  158.    for (n = 4; --n >= 0; )
  159.    {
  160.       zputhex(v, *hdr);
  161.       crc = updcrc(((USHORT) (*hdr++)), crc);
  162.       }
  163.  
  164.    crc = updcrc(((USHORT) 0), crc);
  165.    crc = updcrc(((USHORT) 0), crc);
  166.    zputhex(v, (UBYTE) (crc >> 8));
  167.    zputhex(v, (UBYTE) crc);
  168.  
  169.    /* Make it printable on remote machine */
  170.    sendline(v, '\r');
  171.    sendline(v, '\n');
  172.    /* Uncork the remote in case a fake XOFF has stopped data flow */
  173.    if (type != ZFIN)
  174.       sendline(v, XON);
  175.    }    /* End of void zshhdr() */
  176.  
  177. /**********************************************************
  178.  *    void zsdata() and void zsda32()
  179.  *
  180.  * Send binary array buf of length length, with ending
  181.  * ZDLE sequence frameend
  182.  **********************************************************/
  183. void zsdata(struct Vars *v, short length, USHORT frameend)
  184. {
  185.    UBYTE  *buf, *outptr, c;
  186.    USHORT crc;
  187.    ULONG  crc32;
  188.  
  189. #ifdef DEBUGLOG
  190.    mysprintf(v->Msgbuf, v->Crc32t ? "zsda32: length=%ld end=%lx\n" 
  191.       : "zsdata: length=%ld end=%lx\n", (long) length, (long) frameend);
  192.    dlog(v, v->Msgbuf);
  193. #endif
  194.  
  195.    buf = v->Pktbuf;
  196.    outptr = v->Outbuf + v->Outbuflen;
  197.    crc32 = 0xFFFFFFFFL;            /* zsda32() */
  198.    crc = 0;
  199.  
  200.    while (--length >= 0)
  201.    {
  202.       switch (DLE_actions[c = *buf])
  203.       {
  204.       case 2:
  205.          if (v->Lastzsent != '@')
  206.             goto sendit;
  207.          /* Fallthrough */
  208.       case 1:
  209.          *outptr++ = ZDLE;
  210.          c ^= 0x40;
  211. sendit:
  212.       case 0:
  213.          *outptr++ = v->Lastzsent = c;
  214.          }
  215.       if (v->Crc32t)            /* zsda32() */
  216.      crc32 = UPDC32((0xFF & *buf++), crc32);
  217.       else
  218.      crc = updcrc(((USHORT) (*buf++)), crc);
  219.       }
  220.    *outptr++ = ZDLE;
  221.    *outptr++ = frameend;
  222.    v->Outbuflen = outptr - v->Outbuf;
  223.  
  224.    if (v->Crc32t)                /* zsda32() */
  225.    {
  226.       crc32 = UPDC32(frameend, crc32);
  227.       crc32 = ~crc32;
  228.       for (length = 4; --length >= 0; )
  229.       {
  230.      zsendline(v, (int) crc32);
  231.      crc32 >>= 8;
  232.      }
  233.       }
  234.    else
  235.    {
  236.       crc = updcrc(frameend, crc);
  237.       crc = updcrc(((USHORT) 0), crc);
  238.       crc = updcrc(((USHORT) 0), crc);
  239.       zsendline(v, (UBYTE) (crc >> 8));
  240.       zsendline(v, (UBYTE) crc);
  241.       }
  242.  
  243.    if (frameend == ZCRCW)
  244.       xsendline(v, XON);
  245.    }    /* End of void zsdata() */
  246.  
  247. /**********************************************************
  248.  *    short zrdata(struct Vars *v, UBYTE *buf, short length)
  249.  *
  250.  * Receive array buf of max length with ending ZDLE sequence
  251.  * and CRC-16.  Returns the ending character or error code.
  252.  **********************************************************/
  253. short zrdata(struct Vars *v, UBYTE *buf, short length)
  254. {
  255.    short c, d;
  256.    USHORT crc;
  257.  
  258.    if (v->Rxframeind == ZBIN32)
  259.       return zrdat32(v, buf, length);
  260.  
  261.    crc = v->Rxcount = 0;
  262.    for (;;)
  263.    {
  264.       if ((c = zdlread(v)) & ~0xFF)
  265.       {
  266. crcfoo:
  267.          switch (c)
  268.      {
  269.          case GOTCRCE:
  270.          case GOTCRCG:
  271.          case GOTCRCQ:
  272.          case GOTCRCW:
  273.             crc = updcrc(((d = c) & 0xFF), crc);
  274.             if ((c = zdlread(v)) & ~0xFF)
  275.            goto crcfoo;
  276.             crc = updcrc(c, crc);
  277.             if ((c = zdlread(v)) & ~0xFF)
  278.            goto crcfoo;
  279.             crc = updcrc(c, crc);
  280.             if (crc & 0xFFFF)
  281.         {
  282.                strcpy(v->Msgbuf, "Bad data packet CRC-16 ");
  283.                return ERROR;
  284.                }
  285. #ifdef DEBUGLOG
  286.             mysprintf(v->Msgbuf, "zrdata: cnt = %ld ret = %lx\n",
  287.            (long) v->Rxcount, (long) d);
  288.             dlog(v, v->Msgbuf);
  289. #endif
  290.             return d;
  291.          case GOTCAN:
  292.             strcpy(v->Msgbuf, "Sender canceled ");
  293.             return ZCAN;
  294.          case TIMEOUT:
  295.             strcpy(v->Msgbuf, "Data packet timeout ");
  296.             return c;
  297.          case RCDO:
  298.             return c;
  299.          default:
  300.             strcpy(v->Msgbuf, "Unrecognizable data packet ");
  301.             return c;
  302.             }
  303.          }
  304.       if (--length < 0) 
  305.       {
  306.          strcpy(v->Msgbuf, "Data packet too long ");
  307.          return ERROR;
  308.          }
  309.       ++v->Rxcount;
  310.       *buf++ = c;
  311.       crc = updcrc(c, crc);
  312.       continue;
  313.       }
  314.    }    /* End of short zrdata() */
  315.  
  316. /**********************************************************
  317.  *    short zrdat32(struct Vars *v, UBYTE *buf, short length)
  318.  *
  319.  * Receive array buf of max length with ending ZDLE sequence
  320.  * and CRC-32.  Returns the ending character or error code.
  321.  **********************************************************/
  322. short zrdat32(struct Vars *v, UBYTE *buf, short length)
  323. {
  324.    short c, d;
  325.    ULONG crc32;
  326.  
  327.    crc32 = 0xFFFFFFFFL;
  328.    v->Rxcount = 0;
  329.  
  330.    for (;;)
  331.    {
  332.       if ((c = zdlread(v)) & ~0xFF)
  333.       {
  334. crcfoo:
  335.          switch (c)
  336.      {
  337.          case GOTCRCE:
  338.          case GOTCRCG:
  339.          case GOTCRCQ:
  340.          case GOTCRCW:
  341.         d = c;
  342.         c &= 0xFF;
  343.             crc32 = UPDC32(c, crc32);
  344.             if ((c = zdlread(v)) & ~0xFF)
  345.            goto crcfoo;
  346.             crc32 = UPDC32(c, crc32);
  347.             if ((c = zdlread(v)) & ~0xFF)
  348.            goto crcfoo;
  349.             crc32 = UPDC32(c, crc32);
  350.             if ((c = zdlread(v)) & ~0xFF)
  351.            goto crcfoo;
  352.             crc32 = UPDC32(c, crc32);
  353.             if ((c = zdlread(v)) & ~0xFF)
  354.            goto crcfoo;
  355.             crc32 = UPDC32(c, crc32);
  356.         if (crc32 != 0xDEBB20E3)
  357.         {
  358.                strcpy(v->Msgbuf, "Bad data packet CRC-32 ");
  359.                return ERROR;
  360.                }
  361. #ifdef DEBUGLOG
  362.             mysprintf(v->Msgbuf, "zrdat32: cnt = %ld ret = %lx\n",
  363.            (long) v->Rxcount, (long) d);
  364.             dlog(v, v->Msgbuf);
  365. #endif
  366.             return d;
  367.          case GOTCAN:
  368.             strcpy(v->Msgbuf, "Sender canceled ");
  369.             return ZCAN;
  370.          case TIMEOUT:
  371.             strcpy(v->Msgbuf, "Data packet timeout ");
  372.             return c;
  373.          case RCDO:
  374.             return c;
  375.          default:
  376.             strcpy(v->Msgbuf, "Unrecognizable data packet ");
  377.             return c;
  378.             }
  379.          }
  380.       if (--length < 0) 
  381.       {
  382.          strcpy(v->Msgbuf, "Data packet too long ");
  383.          return ERROR;
  384.          }
  385.       ++v->Rxcount;
  386.       *buf++ = c;
  387.       crc32 = UPDC32(c, crc32);
  388.       continue;
  389.       }
  390.    }    /* End of short zrdat32() */
  391.  
  392. /**********************************************************
  393.  *    short zgethdr(struct Vars *v)
  394.  *
  395.  * Read a ZMODEM header to hdr, either binary or hex.
  396.  *  On success return type of header.
  397.  *  Otherwise return negative on error.
  398.  **********************************************************/
  399. short zgethdr(struct Vars *v)
  400. {
  401.    short c, cancount;
  402.    long n;
  403. #ifdef DEBUGLOG
  404.    UBYTE msgbuf [128];
  405. #endif
  406.  
  407.    n = v->Baud;   /* Max characters before start of frame */
  408.    cancount = 5;
  409. again:
  410.    v->Rxframeind = v->Rxtype = 0;
  411.    switch (c = noxrd7(v))
  412.    {
  413.    case RCDO:
  414.    case TIMEOUT:
  415.       goto fifi;
  416.    case CAN:
  417.       if (--cancount <= 0)
  418.       {
  419.          c = ZCAN;
  420.          goto fifi;
  421.          }
  422.    default:
  423. agn2:
  424.       if (--n <= 0)
  425.       {
  426.          strcpy(v->Msgbuf, "Header search garbage count exceeded ");
  427.          return ERROR;
  428.          }
  429.       if (c != CAN)
  430.      cancount = 5;
  431.       goto again;
  432.    case ZPAD:              /* This is what we want. */
  433.       break;
  434.       }
  435.    cancount = 5;
  436. splat:
  437.    switch (c = noxrd7(v))
  438.    {
  439.    case ZPAD:
  440.       goto splat;
  441.    case RCDO:
  442.    case TIMEOUT:
  443.       goto fifi;
  444.    default:
  445.       goto agn2;
  446.    case ZDLE:              /* This is what we want. */
  447.       break;
  448.       }
  449.  
  450.    switch (c = noxrd7(v))
  451.    {
  452.    case RCDO:
  453.    case TIMEOUT:
  454.       goto fifi;
  455.    case ZBIN:
  456.       v->Rxframeind = ZBIN;
  457.       v->Crc32 = FALSE;
  458.       c =  zrbhdr(v);
  459.       break;
  460.    case ZBIN32:
  461.       v->Crc32 = v->Rxframeind = ZBIN32;
  462.       c =  zrbhdr32(v);
  463.       break;
  464.    case ZHEX:
  465.       v->Rxframeind = ZHEX;
  466.       v->Crc32 = FALSE;
  467.       c =  zrhhdr(v);
  468.       break;
  469.    case CAN:
  470.       if (--cancount <= 0)
  471.       {
  472.          c = ZCAN;
  473.          goto fifi;
  474.          }
  475.       goto agn2;
  476.    default:
  477.       goto agn2;
  478.       }
  479.    v->Rxpos = rclhdr(v);
  480. fifi:
  481.    switch (c)
  482.    {
  483.    case GOTCAN:
  484.       c = ZCAN;
  485.    case ZNAK:
  486.    case ZCAN:
  487.    case ERROR:
  488.    case TIMEOUT:
  489.    case RCDO:
  490.       mysprintf(v->Msgbuf, "%s %s ", frametypes[c + FTOFFSET],
  491.          (c >= 0) ? "header" : "error");
  492. #ifdef DEBUGLOG
  493.    default:
  494.       if (c >= -3 && c <= FRTYPES)
  495.          mysprintf(msgbuf, "zgethdr: %s @ %ld\n", frametypes[c + FTOFFSET],
  496.         v->Rxpos);
  497.       else
  498.          mysprintf(msgbuf, "zgethdr: Unknown type %ld @ %ld\n", (long) c,
  499.         v->Rxpos);
  500.       dlog(v, msgbuf);
  501. #endif
  502.       }
  503.    return c;
  504.    }    /* End of short zgethdr() */
  505.  
  506. /**********************************************************
  507.  *    short zrbhdr(struct Vars *v)
  508.  *
  509.  * Receive a binary style header (type and position)
  510.  **********************************************************/
  511. short zrbhdr(struct Vars *v)
  512. {
  513.    UBYTE *hdr = v->Rxhdr;
  514.    short c, n;
  515.    USHORT crc;
  516.  
  517.    if ((c = zdlread(v)) & ~0xFF)
  518.       return c;
  519.    v->Rxtype = c;
  520.    crc = updcrc(c, 0);
  521.  
  522.    for (n = 4; --n >= 0; )
  523.    {
  524.       if ((c = zdlread(v)) & ~0xFF)
  525.      return c;
  526.       crc = updcrc(c, crc);
  527.       *hdr++ = c;
  528.       }
  529.    if ((c = zdlread(v)) & ~0xFF)
  530.       return c;
  531.    crc = updcrc(c, crc);
  532.    if ((c = zdlread(v)) & ~0xFF)
  533.       return c;
  534.    crc = updcrc(c, crc);
  535.    if (crc & 0xFFFF)
  536.    {
  537.       strcpy(v->Msgbuf, "Bad Header CRC-16 ");
  538.       return ERROR;
  539.       }
  540.    return v->Rxtype;
  541.    }    /* End of short zrbhdr() */
  542.  
  543. /**********************************************************
  544.  *    short zrbhdr32(struct Vars *v)
  545.  *
  546.  * Receive a binary style header (type and position) with
  547.  * 32 bit FCS
  548.  **********************************************************/
  549. short zrbhdr32(struct Vars *v)
  550. {
  551.    UBYTE *hdr = v->Rxhdr;
  552.    short c, n;
  553.    ULONG crc32;
  554.  
  555.    if ((c = zdlread(v)) & ~0xFF)
  556.       return c;
  557.    v->Rxtype = c;
  558.    crc32 = 0xFFFFFFFFL;
  559.    crc32 = UPDC32(c, crc32);
  560. #ifdef DEBUGLOG
  561.    mysprintf(v->Msgbuf, "zrbhdr32: c=%x  crc32=%1x\n", c, crc32);
  562.    dlog(v, v->Msgbuf);
  563. #endif
  564.  
  565.    for (n = 4; --n >= 0; )
  566.    {
  567.       if ((c = zdlread(v)) & ~0xFF)
  568.      return c;
  569.       crc32 = UPDC32(c, crc32);
  570.       *hdr++ = c;
  571. #ifdef DEBUGLOG
  572.       mysprintf(v->Msgbuf, "zrbhdr32: c=%x  crc32=%1x\n", c, crc32);
  573.       dlog(v, v->Msgbuf);
  574. #endif
  575.       }
  576.    for (n = 4; --n >= 0; )
  577.    {
  578.       if ((c = zdlread(v)) & ~0xFF)
  579.      return c;
  580.       crc32 = UPDC32(c, crc32);
  581. #ifdef DEBUGLOG
  582.       mysprintf(v->Msgbuf, "zrbhdr32: c=%x  crc32=%1x\n", c, crc32);
  583.       dlog(v, v->Msgbuf);
  584. #endif
  585.       }
  586.    if (crc32 != 0xDEBB20E3)
  587.    {
  588.       strcpy(v->Msgbuf, "Bad Header CRC-32 ");
  589.       return ERROR;
  590.       }
  591.    return v->Rxtype;
  592.    }    /* End of short zrbhdr32() */
  593.  
  594. /**********************************************************
  595.  *    short zrhhdr(struct Vars *v)
  596.  *
  597.  * Receive a hex style header (type and position)
  598.  **********************************************************/
  599. short zrhhdr(struct Vars *v)
  600. {
  601.    UBYTE *hdr = v->Rxhdr;
  602.    short c, n;
  603.    USHORT crc;
  604.  
  605.    if ((c = zgethex(v)) < 0)
  606.       return c;
  607.    v->Rxtype = c;
  608.    crc = updcrc(c, 0);
  609.  
  610.    for (n = 4; --n >= 0; )
  611.    {
  612.       if ((c = zgethex(v)) < 0)
  613.      return c;
  614.       crc = updcrc(c, crc);
  615.       *hdr++ = c;
  616.       }
  617.    if ((c = zgethex(v)) < 0)
  618.       return c;
  619.    crc = updcrc(c, crc);
  620.    if ((c = zgethex(v)) < 0)
  621.       return c;
  622.    crc = updcrc(c, crc);
  623.    if (crc & 0xFFFF)
  624.    {
  625.       strcpy(v->Msgbuf, "Bad Header CRC ");
  626.       return ERROR;
  627.       }
  628.    if (readock(v, 1) == '\r')
  629.       readock(v, 1);        /* Throw away possible cr/lf */
  630.    return v->Rxtype;
  631.    }    /* End of short zrhhdr() */
  632.  
  633. /**********************************************************
  634.  *    void zputhex(struct Vars *v, UBYTE c)
  635.  *
  636.  * Send a byte as two hex digits
  637.  **********************************************************/
  638. void zputhex(struct Vars *v, UBYTE c)
  639. {
  640.    static char digits[] = "0123456789abcdef";
  641.  
  642.    sendline(v, digits[(c >> 4) & 0x0F]);
  643.    sendline(v, digits[c & 0x0F]);
  644.    }    /* End of void zputhex() */
  645.  
  646. /**********************************************************
  647.  *    void zsendline(struct Vars *v, UBYTE c)
  648.  *
  649.  * Send character c with ZMODEM escape sequence encoding.
  650.  * Escape ZDLE, real DLE, XON, XOFF, and CR following @ (Telenet net escape)
  651.  **********************************************************/
  652. void zsendline(struct Vars *v, UBYTE c)
  653. {
  654.    switch (DLE_actions[c])
  655.    {
  656.    case 2:
  657.       if (v->Lastzsent != '@')
  658.          goto sendit;
  659.       /* Fallthrough */
  660.    case 1:
  661.       xsendline(v, ZDLE);
  662.       c ^= 0x40;
  663. sendit:
  664.    case 0:
  665.       xsendline(v, v->Lastzsent = c);
  666.       }
  667.    }    /* End of void zsendline() */
  668.  
  669. /**********************************************************
  670.  *    short zgethex(struct Vars *v)
  671.  *
  672.  * Decode two lower case hex digits into an 8 bit byte value
  673.  **********************************************************/
  674. short zgethex(struct Vars *v)
  675. {
  676.    short c, n;
  677.  
  678.    if ((n = noxrd7(v)) < 0)
  679.       return n;
  680.    n -= '0';
  681.    if (n > 9)
  682.       n -= ('a' - ':');
  683.    if (n & ~0xF)
  684.       return ERROR;
  685.  
  686.    if ((c = noxrd7(v)) < 0)
  687.       return c;
  688.    c -= '0';
  689.    if (c > 9)
  690.       c -= ('a' - ':');
  691.    if (c & ~0xF)
  692.       return ERROR;
  693.  
  694.    return (short) (n << 4 | c);
  695.    }    /* End of short zgethex() */
  696.  
  697. /**********************************************************
  698.  *    short zdlread(struct Vars *v)
  699.  *
  700.  * Read a byte, checking for ZMODEM escape encoding
  701.  * including CAN*5 which represents a quick abort.
  702.  **********************************************************/
  703. short zdlread(struct Vars *v)
  704. {
  705.    short c;
  706.  
  707.    if ((c = readock(v, v->Rxtimeout)) != ZDLE)
  708.       return c;
  709.    if ((c = readock(v, v->Rxtimeout)) < 0)
  710.       return c;
  711.    if (c == CAN && (c = readock(v, v->Rxtimeout)) < 0)
  712.       return c;
  713.    if (c == CAN && (c = readock(v, v->Rxtimeout)) < 0)
  714.       return c;
  715.    if (c == CAN && (c = readock(v, v->Rxtimeout)) < 0)
  716.       return c;
  717.    switch (c)
  718.    {
  719.    case CAN:
  720.       return GOTCAN;
  721.    case ZCRCE:
  722.    case ZCRCG:
  723.    case ZCRCQ:
  724.    case ZCRCW:
  725.       return (short) (c | GOTOR);
  726.    case ZRUB0:
  727.       return 0x7F;
  728.    case ZRUB1:
  729.       return 0xFF;
  730.    default:
  731.       if ((c & 0x60) ==  0x40)
  732.      return (short) (c ^ 0x40);
  733.       break;
  734.       }
  735.    strcpy(v->Msgbuf, "Bad ZMODEM escape sequence ");
  736.    return ERROR;
  737.    }    /* End of short zdlread() */
  738.  
  739. /**********************************************************
  740.  *    short noxrd7(struct Vars *v)
  741.  *
  742.  * Read a character from the modem line with timeout.
  743.  * Eat parity, XON and XOFF characters.
  744.  **********************************************************/
  745. short noxrd7(struct Vars *v)
  746. {
  747.    short c;
  748.  
  749.    for (;;)
  750.    {
  751.       if ((c = readock(v, v->Rxtimeout)) < 0)
  752.      return c;
  753.       switch (c &= 0x7F)
  754.       {
  755.       case XON:
  756.       case XOFF:
  757.          continue;
  758.       default:
  759.          return c;
  760.          }
  761.       }
  762.    }    /* short noxrd7() */
  763.  
  764. /**********************************************************
  765.  *    void stohdr(struct Vars *v, long pos)
  766.  *
  767.  * Store long integer pos in Txhdr
  768.  **********************************************************/
  769. void stohdr(struct Vars *v, long pos)
  770. {
  771.    v->Txhdr[ZP0] = pos;
  772.    pos >>= 8;
  773.    v->Txhdr[ZP1] = pos;
  774.    pos >>= 8;
  775.    v->Txhdr[ZP2] = pos;
  776.    pos >>= 8;
  777.    v->Txhdr[ZP3] = pos;
  778.    }    /* End of void stohdr() */
  779.  
  780. /**********************************************************
  781.  *    long rclhdr(struct Vars *v)
  782.  *
  783.  * Recover a long integer from a header
  784.  **********************************************************/
  785. long rclhdr(struct Vars *v)
  786. {
  787.    long l;
  788.  
  789.    l = v->Rxhdr[ZP3];
  790.    l = (l << 8) | v->Rxhdr[ZP2];
  791.    l = (l << 8) | v->Rxhdr[ZP1];
  792.    l = (l << 8) | v->Rxhdr[ZP0];
  793.    return l;
  794.    }    /* End of long rclhdr() */
  795. /* End of Zm.c source */
  796.